#include "SD_Card_Handler.h"

#pragma MESSAGE DISABLE C4301

uint8 u8SD_RxBuffer[6];

union 
{
    uint32 u32SD_Argument;
    uint8 u8SD_Argument[4];
} SD_Argument;

void vfnSD_ClockInit (void)
{
    vfnSPI_PrescalerSelect (SPI_PRESCALER_5);
    vfnSPI_BaudRateSelect (SPI_BAUDRATE_DIVIDER_4);
}

void vfnSD_MaxClock (void)
{
    vfnSPI_PrescalerSelect (SPI_PRESCALER_2);
    vfnSPI_BaudRateSelect (SPI_BAUDRATE_DIVIDER_2);
}

#pragma INLINE
void vfnSD_AssertSS (void)
{
    SS_PIN = 0;
}

#pragma INLINE
void vfnSD_UnassertSS (void)
{
    SS_PIN = 1;
}

uint8 u8SD_SendCommand (uint8 u8command, uint8 u8responselength)
{
    uint8 u8counter;
    uint8 u8temp;
    
    vfnSD_AssertSS ();
    vfnSPI_SendByte (u8command);
    
    for(u8counter = 0; u8counter < 4; u8counter++)
    {
        vfnSPI_SendByte (SD_Argument.u8SD_Argument[u8counter]);
    }
    vfnSPI_SendByte (SD_CRC);
    
    /* Wait for a response */
    u8counter = 0;
    do
    {
        u8temp = u8SPI_ReadData (); 
        u8counter++;
          
    } while(((u8temp & 0x80) != 0) && u8counter < SD_CMD_TIMEOUT);
    
    if (u8counter >= SD_CMD_TIMEOUT) // If command timed out, just cancel
    {
        vfnSD_UnassertSS ();
        return 0;
    }
     
    for(u8counter = 0; u8counter < u8responselength; u8counter++)
    {
        u8SD_RxBuffer[u8counter] = u8temp;
        u8temp = u8SPI_ReadData ();    
    }
       
    vfnSD_UnassertSS ();    
    return 1;
    
}

uint8 u8SD_Initialize (void)
{
    uint8 u8counter;
    vfnSD_ClockInit ();
    
    SD_Argument.u32SD_Argument = 0x00000000;
    
    /* Delay for at least 74 clock cycles. This means we need to have
    at least 74 clock pulses with no data on the bus, using SPI mode
    we only have to send at least 10 idle bytes (0xFF) */
    
    vfnSD_AssertSS ();
    vfnSPI_Delay(20);
    vfnSD_UnassertSS ();
    vfnSPI_Delay(2);
    
    if(!u8SD_SendCommand (SD_COMMAND_0, SD_COMMAND_0_RESPONSE))
    {
        return 0;
    }
    
    u8counter = 0;
    
    do
    {
        u8counter++;
        
        if(u8SD_SendCommand (SD_COMMAND_55, SD_COMMAND_55_RESPONSE))
        {
            (void)u8SD_SendCommand (SD_COMMAND_41, SD_COMMAND_41_RESPONSE);
        }
        else
        {
            u8counter = SD_INIT_TIMEOUT;
        }
    } while(((u8SD_RxBuffer[0] & 0x01) != 0x01) && (u8counter < SD_INIT_TIMEOUT));
    
    if (u8counter >= SD_INIT_TIMEOUT)
    {
        return 0;
    }
    
    if (!u8SD_SendCommand(SD_COMMAND_58, SD_COMMAND_58_RESPONSE))
    {
        return 0;    
    }
    
    if ((u8SD_RxBuffer[2] & 0xC0) != 0xC0)
    {
        return 0;
    }
   
    vfnSD_MaxClock();
    return 1;
        
}

uint8 u8SD_WriteBlock (uint32 u32blockaddr, uint8 *u8data, uint8 u8size)
{
    uint16 u16counter;
    
    SD_Argument.u32SD_Argument = u32blockaddr << SD_BLOCKSIZE_BITS;
    
    if (!u8SD_SendCommand(SD_COMMAND_24, SD_COMMAND_24_RESPONSE))
    {
        return 0;
    }
        
    if (u8SD_RxBuffer[0] != 0)  // Check for errors
    {
        return 0;
    }
    
    vfnSD_AssertSS();
    
    (void)u8SPI_ReadData();
    
    vfnSPI_SendByte (0xFE);
    
    for (u16counter = 0; u16counter < u8size; u16counter++)
    {
        vfnSPI_SendByte (u8data[u16counter]);
    }
    
    for (u16counter = u8size; u16counter < SD_BLOCKSIZE; u16counter++)
    {
        vfnSPI_SendByte(0xAA); 
    }
    
    // Ignore checksums as they are not enabled by default on SPI mode
    vfnSPI_Delay(4);
    
    // Wait for write to be done on the card
    while (u8SPI_ReadData() != 0xFF);
    
    vfnSD_UnassertSS();
    
    vfnSPI_Delay(2);    
    
    return 1;
        
}

uint8 u8SD_ReadBlock (uint32 u32blockaddr)
{
    SD_Argument.u32SD_Argument = u32blockaddr << SD_BLOCKSIZE_BITS;        
   
    return 0;       
}

